package com.jvup.gameshow.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.widget.LinearLayout;
import android.widget.RadioButton;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.view.SupportMenuInflater;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.appcompat.view.menu.MenuBuilder.Callback;
import androidx.appcompat.view.menu.MenuItemImpl;
import androidx.appcompat.widget.TintTypedArray;
import androidx.appcompat.widget.TooltipCompat;
import androidx.core.view.ViewCompat;
import androidx.customview.view.AbsSavedState;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.transition.AutoTransition;
import androidx.transition.TransitionManager;
import androidx.transition.TransitionSet;

import com.google.android.material.internal.TextScale;
import com.jvup.common.utils.Logger;
import com.jvup.gameshow.R;

import java.lang.reflect.Field;

/**
 * 底部导航菜单控件<br />
 * android 菜单系统采用了 MVP模式构建， M:菜单 V:控件 P:业务处理交互 MenuView接口，M菜单更新通过 菜单构建器对象的 onItemsChanged通知到P层，转交给V做UI更新处理，
 * 目前该对象舍弃了P，未支持到P，P的部分功能由BottomNavigationView内完成了。固如果需要完全遵循菜单系统可以参考google的BottomNavigationView
 */
@SuppressLint("RestrictedApi")
public class BottomNavigationView extends LinearLayout {

    /**
     * 菜单子View绑定Menu对象到setTag的标签,用于点击后提取菜单对象
     */
    private final int MENU_ITEM_TAG = 3 << 24;
    /**
     * View回收状态保存KEY，用在Activity长时间未使用回收时保存当前选中的菜单ID
     */
    private final String SELECTED_ITEM_ID_KEY = "selectedItemId";
    /**
     * 切换菜单按钮时的动画集
     */
    private final TransitionSet transitionSet;

    /**
     * 菜单对象构建器，包含了菜单对象model的容器。
     */
    private final MenuBuilder menu;
    /**
     * 菜单控件的默认点击事件。
     */
    private final OnClickListener onClickListener = view -> {
        MenuItem item = (MenuItem) view.getTag(MENU_ITEM_TAG);
        if (!BottomNavigationView.this.menu.performItemAction(item, null, 0)) {
            item.setChecked(true);
        }
    };

    /**
     * 菜单更新阻断状态，如果正在使用菜单则抛弃之后的一切菜单更新行为。
     */
    private volatile boolean updateSuspended = false;

    /**
     * 菜单填充器，默认实现了菜单的XML解析并填充一个MenuBuilder
     */
    private MenuInflater menuInflater;

    private int itemIconSpace;

    /**
     * 菜单文本的颜色集，支持选中和未选中
     */
    private ColorStateList itemTextColorFromUser;
    /**
     * 菜单文本的字体大小
     */
    private int itemTextSize;

    /**
     * 菜单子选项控件的集合
     */
    private RadioButton[] buttons;

    /**
     * 当前选中的菜单项ID
     */
    private int selectedItemId;
    /**
     * 当前选中的菜单项位置
     */
    private int selectedItemPosition;

    /**
     * 选中菜单选项事件监听器
     */
    private OnNavigationItemSelectedListener selectedListener;
    /**
     * 恢复重建菜单选项事件监听器
     */
    private OnNavigationItemReselectedListener reselectedListener;

    public BottomNavigationView(Context context) {
        this(context, null);
    }

    public BottomNavigationView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BottomNavigationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public BottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        // 初始化菜单构建器
        this.menu = new BottomNavigationMenu(context);
        // 设置menu状态修改时的回掉监听
        this.menu.setCallback(new Callback() {
            @Override
            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
                if (reselectedListener != null && item.getItemId() == getSelectedItemId()) {
                    reselectedListener.onNavigationItemReselected(item);
                    return true;
                } else {
                    return selectedListener != null && !selectedListener.onNavigationItemSelected(item);
                }
            }
            @Override
            public void onMenuModeChange(MenuBuilder menu) {}
        });

        // 初始化动画集
        this.transitionSet = new AutoTransition();
        this.transitionSet.setOrdering(0);
        this.transitionSet.setDuration(115L);
        this.transitionSet.setInterpolator(new FastOutSlowInInterpolator());
        this.transitionSet.addTransition(new TextScale());

        // 加载BottomNavigationView支持XML的属性集
        TintTypedArray tintTypedArray = TintTypedArray.obtainStyledAttributes(context, attrs, R.styleable.BottomNavigationView, defStyleAttr, R.style.Widget_Design_BottomNavigationView);

        // 读取菜单选项控件背景属性，暂时没有需求留作扩展
//        int itemBackground = tintTypedArray.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
//        this.setItemBackgroundRes(itemBackground);

        this.selectedItemPosition = tintTypedArray.getInt(R.styleable.BottomNavigationView_selectPosition, 0);

        // 读取菜单选项Icon与文本的间距
        setItemIconSpace(tintTypedArray.getDimensionPixelSize(R.styleable.BottomNavigationView_itemIconSpace, 0));

        // 读取菜单选项控件文本字体大小，以像素大小读取，默认如果未设置取0使用系统字体大小
        this.setItemTextSize(TypedValue.COMPLEX_UNIT_PX,tintTypedArray.getDimensionPixelSize(R.styleable.BottomNavigationView_itemTextSize, 0));
        // 读取菜单选项控件文本字体颜色
        if (tintTypedArray.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
            this.setItemTextColor(tintTypedArray.getColorStateList(R.styleable.BottomNavigationView_itemTextColor));
        }

        // 读取菜单选项控件Icon的切换颜色，该功能暂无需求固未支持，作用是使用ICON着色功能替代图片切换，一张图在不同状态下着色不同
//        if (tintTypedArray.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
//            this.setIconTintList(tintTypedArray.getColorStateList(R.styleable.BottomNavigationView_itemIconTint));
//        } else {
//            this.setIconTintList(this.menuView.createDefaultColorStateList(16842808));
//        }
        // 读取Icon的大小，暂无需求不支持
//        this.setItemIconSize(tintTypedArray.getDimensionPixelSize(R.styleable.BottomNavigationView_itemIconSize, this.getResources().getDimensionPixelSize(R.dimen.design_bottom_navigation_icon_size)));

        // 读取View的层级，可设置Z轴的层级关系。
        if (tintTypedArray.hasValue(R.styleable.BottomNavigationView_elevation)) {
            ViewCompat.setElevation(this, (float)tintTypedArray.getDimensionPixelSize(R.styleable.BottomNavigationView_elevation, 0));
        }

        // 读取XML描述的MENU数据解析填充Menu数据
        if (tintTypedArray.hasValue(R.styleable.BottomNavigationView_menu)) {
            this.inflateMenu(tintTypedArray.getResourceId(R.styleable.BottomNavigationView_menu, 0));
        }

        tintTypedArray.recycle();

    }

    /**
     * 用时构建填充器
     * @return menu.xml解析填充器
     */
    private MenuInflater getMenuInflater() {
        if (this.menuInflater == null) {
            this.menuInflater = new SupportMenuInflater(this.getContext());
        }
        return this.menuInflater;
    }

    /**
     * 菜单更新阻断状态更新
     * @param updateSuspended 更新状态
     */
    private void setUpdateSuspended(boolean updateSuspended) {
        this.updateSuspended = updateSuspended;
    }

    /**
     * 通过菜单对象集合构建菜单子控件，如果菜单内容为空则会回收子控件集合。该方法目前只会被updateMenuView在检查到数据与View不匹配时调用，
     * 犹豫该方法有状态检查，固在其他地方使用时一定注意状态，一般情况下尽量不修改
     */
    private void buildMenuView() {

        if(this.updateSuspended) {
            return;
        }

        this.removeAllViews();
        final int menuSize = this.menu.size();

        if(menuSize == 0) {
            Logger.d("BottomNavigationView ==== menu is empty");
            this.selectedItemId = 0;
            this.selectedItemPosition = 0;
            this.buttons = null;
            return;
        }

        this.buttons = new RadioButton[menuSize];

        for(int index = 0; index < menuSize; index++) {
            MenuItemImpl menuItem = (MenuItemImpl) this.menu.getItem(index);

            this.setUpdateSuspended(true);
            menuItem.setCheckable(true);
            this.setUpdateSuspended(false);

            Logger.d("BottomNavigationView ====== " + index + ":" + menuItem.getTitle());

            RadioButton radioButton;
            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT,1);
            if((radioButton = this.buttons[index]) == null) {
                radioButton = new RadioButton(getContext());
                radioButton.setButtonDrawable(null);
                radioButton.setGravity(Gravity.CENTER);
                this.buttons[index] = radioButton;
            }
            radioButton.setLayoutParams(layoutParams);

            radioButton.setTextSize(TypedValue.COMPLEX_UNIT_PX,this.itemTextSize);
            radioButton.setTextColor(this.itemTextColorFromUser);

//            radioButton.setIconTintList(this.itemIconTint);
//            radioButton.setIconSize(this.itemIconSize);

            radioButton.setTag(MENU_ITEM_TAG,menuItem);
            radioButton.setId(menuItem.getItemId());
            if(TextUtils.isEmpty(menuItem.getTitle())) {
                layoutParams.bottomMargin =  -(this.itemTextSize+itemIconSpace);
            } else {
                radioButton.setText(menuItem.getTitle());
            }
            Drawable left  = null; //menuItem.getIcon();
            Drawable top   = menuItem.getIcon();
            Drawable right = null; //menuItem.getIcon();
            Drawable bottom= null; //menuItem.getIcon();
            radioButton.setCompoundDrawablesWithIntrinsicBounds(left,top,right,bottom);
            radioButton.setCompoundDrawablePadding(itemIconSpace);
            radioButton.refreshDrawableState();//替代调用 radioButton.setCheckable(menuItem.isCheckable());
            radioButton.setChecked(menuItem.isChecked());
            radioButton.setEnabled(menuItem.isEnabled());
            if (!TextUtils.isEmpty(menuItem.getContentDescription())) {
                this.setContentDescription(menuItem.getContentDescription());
            }
            TooltipCompat.setTooltipText(radioButton, menuItem.getTooltipText());
            radioButton.setVisibility(menuItem.isVisible() ? VISIBLE : GONE);


//            child.setTextAppearanceInactive(this.itemTextAppearanceInactive);
//            child.setTextAppearanceActive(this.itemTextAppearanceActive);
//
//            if (this.itemBackground != null) {
//                child.setItemBackground(this.itemBackground);
//            } else {
//                child.setItemBackground(this.itemBackgroundRes);
//            }
//
//            child.setShifting(shifting);
//            child.setLabelVisibilityMode(this.labelVisibilityMode);
//            child.setItemPosition(i);


            radioButton.setOnClickListener(this.onClickListener);

            this.addView(radioButton);
        }

        this.selectedItemPosition = Math.min(this.menu.size() - 1, this.selectedItemPosition);
        this.menu.getItem(this.selectedItemPosition).setChecked(true);
//        ((MenuItemImpl)this.menu.getItem(this.selectedItemPosition).setChecked(true)).invoke();
    }

    /**
     * 更新菜单控件状态
     */
    private void updateMenuView() {

        Logger.d("BottomNavigationView ==== menu update");

        if (this.updateSuspended) {
            return;
        }

        if (this.menu == null) {
            return;
        }

        final int menuSize = this.menu.size();

        if(this.buttons == null || menuSize != this.buttons.length) {
            Logger.d("BottomNavigationView ==== menuView is empty");
            buildMenuView();
            return;
        }

        int previousSelectedId = this.selectedItemId;

        for(int i = 0; i < menuSize; ++i) {
            MenuItem item = this.menu.getItem(i);
            if (item.isChecked()) {
                this.selectedItemId = item.getItemId();
                this.selectedItemPosition = i;
            }
        }

        if (previousSelectedId != this.selectedItemId) {
            TransitionManager.beginDelayedTransition(this, this.transitionSet);
        }

        for(int i = 0; i < menuSize; ++i) {
            this.setUpdateSuspended(true);
//            this.buttons[i].setLabelVisibilityMode(this.labelVisibilityMode);
            this.buttons[i].setChecked(this.menu.getItem(i).isChecked());
            this.setUpdateSuspended(false);
        }
    }

    /**
     * 填充菜单对象
     * @param resId 填充源XML
     */
    public void inflateMenu(int resId) {
        this.setUpdateSuspended(true);
        this.getMenuInflater().inflate(resId, this.menu);
        this.setUpdateSuspended(false);
        this.updateMenuView();
    }

    public void setItemIconSpace(int itemIconSpace){
        this.itemIconSpace = itemIconSpace;
        if (this.buttons != null) {
            final RadioButton[] buttons = this.buttons;
            int length = buttons.length;
            for(int index = 0; index < length; ++index) {
                RadioButton item = buttons[index];
                item.setCompoundDrawablePadding(itemIconSpace);
            }
        }
    }

    /**
     * 设置子项View的字体大小，
     * @param textSize SP单位的字体大小
     */
    public void setItemTextSize(float textSize){
        float textSizePX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,textSize,getResources().getDisplayMetrics());
        setItemTextSize(TypedValue.COMPLEX_UNIT_PX, (int) textSizePX);
    }

    /**
     * 指定单位的字体大小
     * @param unit
     * @param textSize
     */
    public void setItemTextSize(int unit, int textSize) {
        this.itemTextSize = textSize;
        if (this.buttons != null) {
            final RadioButton[] buttons = this.buttons;
            int length = buttons.length;
            for(int index = 0; index < length; ++index) {
                RadioButton item = buttons[index];
                item.setTextSize(unit,itemTextSize);
            }
        }
    }

    /**
     * 菜单字体颜色
     * @param color 颜色集
     */
    public void setItemTextColor(ColorStateList color) {
        this.itemTextColorFromUser = color;
        if (this.buttons != null) {
            final RadioButton[] buttons = this.buttons;
            int length = buttons.length;
            for(int index = 0; index < length; ++index) {
                RadioButton item = buttons[index];
                item.setTextColor(color);
            }
        }
    }

    /**
     * 菜单容器对象
     * @return 菜单容器
     */
    @NonNull
    public Menu getMenu() {
        return this.menu;
    }

    /**
     * 选中的菜单项ID
     * @return ID
     */
    @IdRes
    public int getSelectedItemId() {
        return this.selectedItemId;
    }

    /**
     * 设置选中菜单时监听器
     * @param listener 监听器
     */
    public void setOnNavigationItemSelectedListener(@Nullable OnNavigationItemSelectedListener listener) {
        this.selectedListener = listener;
    }

    /**
     * 设置恢复时监听器
     * @param listener
     */
    public void setOnNavigationItemReselectedListener(@Nullable OnNavigationItemReselectedListener listener) {
        this.reselectedListener = listener;
        // 为了设置初始化时能够触发一次重置页面监听。如果不需要这种设定可以删除这一段。
        if(null != this.reselectedListener) {
            int size = this.menu.size();
            for(int i = 0; i < size; ++i) {
                MenuItem item = this.menu.getItem(i);
                if (this.selectedItemId == item.getItemId()) {
                    this.reselectedListener.onNavigationItemReselected(item);
                }
            }
        }
    }

    /**
     * 回收是保存事件
     * @return
     */
    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.menuPresenterState = new Bundle();
        savedState.menuPresenterState.putInt(SELECTED_ITEM_ID_KEY, selectedItemId);

        this.menu.savePresenterStates(savedState.menuPresenterState);

        return savedState;
    }

    /**
     * 恢复时重建事件
     * @param state
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
        } else {
            SavedState savedState = (SavedState)state;
            super.onRestoreInstanceState(savedState.getSuperState());

            this.tryRestoreSelectedItemId(savedState.menuPresenterState.getInt(SELECTED_ITEM_ID_KEY));

            this.menu.restorePresenterStates(savedState.menuPresenterState);
        }
    }

    /**
     * 异常恢复选中菜单
     * @param itemId
     */
    void tryRestoreSelectedItemId(int itemId) {
        int size = this.menu.size();

        for(int i = 0; i < size; ++i) {
            MenuItem item = this.menu.getItem(i);
            if (itemId == item.getItemId()) {
                this.selectedItemId = itemId;
                this.selectedItemPosition = i;
                item.setChecked(true);
                break;
            }
        }

    }

    /**
     * 释放时保存对象容器
     */
    static class SavedState extends AbsSavedState {
        Bundle menuPresenterState;
        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
                return new SavedState(in, loader);
            }

            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in, (ClassLoader)null);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };

        public SavedState(Parcelable superState) {
            super(superState);
        }

        public SavedState(Parcel source, ClassLoader loader) {
            super(source, loader);
            this.readFromParcel(source, loader);
        }

        public void writeToParcel(@NonNull Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeBundle(this.menuPresenterState);
        }

        private void readFromParcel(Parcel in, ClassLoader loader) {
            this.menuPresenterState = in.readBundle(loader);
        }
    }

    /**
     * 自定义菜单构建起，用来监管构建菜单行为
     */
    private class BottomNavigationMenu extends MenuBuilder {

        private final Field mPreventDispatchingItemsChangedField;

        public static final int MAX_ITEM_COUNT = 5;

        public BottomNavigationMenu(Context context) {
            super(context);
            Field field = null;
            try {
                field = MenuBuilder.class.getDeclaredField("mPreventDispatchingItemsChanged");
                field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            mPreventDispatchingItemsChangedField = field;
        }

        public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
            throw new UnsupportedOperationException("BottomNavigationView does not support submenus");
        }

        protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
            if (this.size() + 1 > MAX_ITEM_COUNT) {
                throw new IllegalArgumentException("Maximum number of items supported by BottomNavigationView is 5. Limit can be checked with BottomNavigationView#getMaxItemCount()");
            } else {
                this.stopDispatchingItemsChanged();
                MenuItem item = super.addInternal(group, id, categoryOrder, title);
                if (item instanceof MenuItemImpl) {
                    // 关闭从menu.xml配置中读取选中状态，参见MenuItemImpl.setChecked()方法，在这里为了使用selectedItemId控制选中项
                    ((MenuItemImpl)item).setExclusiveCheckable(true);
                    // 开启从menu.xml配置中读取选中状态，
//                    ((MenuItemImpl)item).setExclusiveCheckable(false);
                }

                this.startDispatchingItemsChanged();
                return item;
            }
        }

        @Override
        public void onItemsChanged(boolean structureChanged) {
            if (!preventDispatchingItemsChanged()) {
                stopDispatchingItemsChanged();
                updateMenuView();
                startDispatchingItemsChanged();
            }
            super.onItemsChanged(structureChanged);
        }

        private boolean preventDispatchingItemsChanged(){
            if(mPreventDispatchingItemsChangedField == null) {
                return false;
            }
            try {
                return (boolean) mPreventDispatchingItemsChangedField.get(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return false;
        }

    }

    /**
     * 恢复时选中事件监听接口
     */
    public interface OnNavigationItemReselectedListener {
        void onNavigationItemReselected(@NonNull MenuItem menuItem);
    }

    /**
     * 选中菜单事件监听接口
     */
    public interface OnNavigationItemSelectedListener {
        boolean onNavigationItemSelected(@NonNull MenuItem menuItem);
    }

}
